package indi.zhk.nocturne.ioc.factory;

import indi.zhk.nocturne.ioc.entity.BeanDefinition;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 赵洪苛
 * @date 2021/6/19 17:44
 **/
public abstract class AbstractBeanFactory implements BeanFactory {

    protected Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /**
     * 通过对象ID获取
     *
     * @param name 对象ID
     * @return 实例对象
     */
    @Override
    public Object getBean(String name) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null) {
            return null;
        }
        if (!beanDefinition.getSingleton() || beanDefinition.getBean() == null) {
            return doCreateBean(beanDefinition);
        } else {
            return beanDefinition.getBean();
        }
    }

    /**
     * 通过类获取
     *
     * @param clazz 类
     * @return 实例对象
     */
    @Override
    public <T> T getBean(Class<T> clazz) {
        BeanDefinition beanDefinition = null;
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            Class<?> beanClass = entry.getValue().getBeanClass();
            if (clazz.isAssignableFrom(beanClass)) {
                if (beanClass == clazz) {
                    beanDefinition = entry.getValue();
                    break;
                }
                beanDefinition = entry.getValue();
            }
        }
        if (beanDefinition == null) {
            return null;
        }
        if (!beanDefinition.getSingleton() || beanDefinition.getBean() == null) {
            return (T) doCreateBean(beanDefinition);
        } else {
            return (T) beanDefinition.getBean();
        }
    }

    /**
     * 注册实例对象的定义
     *
     * @param name           对象名
     * @param beanDefinition 实例对象
     */
    @Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(name, beanDefinition);
    }

    /**
     * 创建bean实例对象
     * @param beanDefinition bean定义对象
     * @return bean实例对象
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition);

    public void populateBeans() {
        for (Map.Entry<String, BeanDefinition> item : beanDefinitionMap.entrySet()) {
            doCreateBean(item.getValue());
        }
    }
}
